package xj.graph2d.app.prop;

import static xj.app.BaseApplicationFrame.getResourceString;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;

import javax.swing.JFrame;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

import xj.graph2d.table.FeatureTable;
import xj.graph2d.table.FeatureTableEntry;
import xj.model.uml.BasicModelElement;
import xj.model.uml.NamedElement;

public class TagField extends FeatureListField {

  public TagField() {
    super();
    if (editor != null) {
      editor.setToolTipText("Tagged values");
    }
  }

  public TagField(JFrame owner) {
    super(owner, getResourceString("Tags.text"),
	  getResourceString("Tags.dialog.title"),
	  false, false);
    if (editor != null) {
      editor.setToolTipText(getResourceString("Tags.edit.tip"));
    }
  }

  @Override
  protected void updateTips() {
    if (editor != null) {
      String prefix = "<html><body bgcolor='white'><b>Tagged values</b><br>";
      String suffix = "</body></html>";
      String text = null;
      if (model != null) {
	Map<String, String> tags = model.getTags();
	if (tags != null && !tags.isEmpty()) {
	  StringBuilder sb = new StringBuilder();
	  Iterator<String> iter = tags.keySet().iterator();
	  while (iter.hasNext()) {
	    sb.append("&nbsp;&nbsp;");
	    String k = iter.next();
	    String v = tags.get(k);
	    sb.append(k + "=" + v);
	    sb.append("<br>");
	  }
	  text = sb.toString();
	}
      }
      if (text == null) { 
	text = "&nbsp;&nbsp;<i>none</i>";
      }
      editor.setToolTipText(prefix + text + suffix);    
    }
  }

  @Override
  public void updateEditorValue() {
    java.util.List<FeatureTableEntry> entries = featurePanel.getEntries();
    if (entries != null) {
      entries.clear();
    } else {
      entries = new ArrayList<FeatureTableEntry>();
    }
    if (model != null) {
      Map<String, String> tags = model.getTags();
      if (tags != null) {
	Iterator<Map.Entry<String, String>> iter = tags.entrySet().iterator();
	while (iter.hasNext()) {
	  Map.Entry<String, String> e = iter.next();
	  entries.add(new TagEntry(e.getKey(), e.getValue()));
	}
      }
    }
    if (entries.isEmpty()) {
      entries.add(makeNewEntry());
    }
    featurePanel.setEntries(entries);

    if (featureDialog != null) {
      String name = null;
      String element = null;
      if (model instanceof NamedElement) {
	name = ((NamedElement) model).getName();
      }
      if (name == null || name.length() == 0) {
	name = "<unnamed>";
      }
      element = "[" + model.getElementName() + "]";
      featurePanel.setTableTitle("Tagged values of", name, element);
    }
  }

  @Override
  public void updateModelValue() {
    java.util.List<FeatureTableEntry> entries = featurePanel.getEntries();
    if (model != null) {
      model.removeAllTags();
      if (entries != null) {
	Iterator<FeatureTableEntry> iter = entries.iterator();
	while (iter.hasNext()) {
	  FeatureTableEntry fe = iter.next();
	  if (fe instanceof TagEntry) {
	    TagEntry entry = (TagEntry) fe;
	    String tname = entry.getName();
	    String tvalue = entry.getValue();
	    if (tname != null && tname.length() > 0 && tvalue != null
		&& tvalue.length() > 0) {
	      model.setTagValue(tname, tvalue);
	    }
	  }
	}
      }
      updateTips();
    }
  }

  static FeatureTableEntry proto = new TagEntry();

  @Override
  public FeatureTableEntry getPrototype() {
    return proto;
  }

  @Override
  public FeatureTableEntry makeNewEntry() {
    return new TagEntry();
  }

}

class TagEntry implements FeatureTableEntry {

  // position of each column
  public static final int NAME_COLUMN = 0;

  public static final int VALUE_COLUMN = 1;

  public static final int DELETE_COLUMN = 2;

  public static final String[] columnNames = { "Name", "Value", "Delete", };

  public static final String[] columnTips = { "Name of the tag",
      "Value of the tag", "Delete the marked tag", };

  public static final Comparator[] comparators = {
      new FeatureEntryComparator(NAME_COLUMN),
      new FeatureEntryComparator(VALUE_COLUMN), null, };

  public static TableCellEditor[] editors = new TableCellEditor[3];

  public static TableCellRenderer[] renderers = { null, null,
      new FeatureTable.GrayBooleanRenderer(), // for Delete
  };

  public static final int[] columnWidths = { 50, 50, 20, };

  public TagEntry() {
  }

  public TagEntry(String name, String value) {
    this.name = name;
    this.value = value;
  }

  public int getColumnCount() {
    return columnNames.length;
  }

  public String getColumnName(int col) {
    if (col >= 0 && col < columnNames.length) {
      return columnNames[col];
    }
    return null;
  }

  public Object getColumnValue(int col) {
    if (col >= 0 && col < columnNames.length) {
      switch (col) {
      case NAME_COLUMN:
	return name;
      case VALUE_COLUMN:
	return value;
      case DELETE_COLUMN:
	return deleted;
      }
    }
    return null;
  }

  public void setColumnValue(int col, Object v) {
    if (col >= 0 && col < columnNames.length) {
      switch (col) {
      case NAME_COLUMN:
	if (v != null) {
	  name = v.toString();
	} else {
	  name = null;
	}
	break;
      case VALUE_COLUMN:
	if (v != null) {
	  value = v.toString();
	} else {
	  value = null;
	}
	break;
      case DELETE_COLUMN:
	if (v instanceof Boolean) {
	  deleted = ((Boolean) v).booleanValue();
	}
	break;
      }
    }
  }

  public String getColumnTip(int col) {
    if (col >= 0 && col < columnTips.length) {
      return columnTips[col];
    }
    return null;
  }

  public Class getColumnClass(int col) {
    switch (col) {
    case NAME_COLUMN:
      return String.class;
    case VALUE_COLUMN:
      return String.class;
    case DELETE_COLUMN:
      return Boolean.class;
    default:
      return String.class;
    }
  }

  public Comparator getColumnComparator(int col) {
    if (col >= 0 && col < comparators.length) {
      return comparators[col];
    }
    return null;
  }

  public TableCellEditor getColumnEditor(int col) {
    if (col >= 0 && col < editors.length) {
      return editors[col];
    }
    return null;
  }

  public boolean isColumnEditable(int col) {
    if (col >= 0 && col < columnNames.length) {
      return true;
    }
    return false;
  }

  public TableCellRenderer getColumnRenderer(int col) {
    if (col >= 0 && col < renderers.length) {
      return renderers[col];
    }
    return null;
  }

  public int getColumnWidth(int col) {
    if (col >= 0 && col < columnWidths.length) {
      return columnWidths[col];
    }
    return -1;
  }

  public String getName() {
    return name;
  }

  public String getValue() {
    return value;
  }

  public BasicModelElement getModelElement() {
    return null;
  }

  public boolean isDeleted() {
    return deleted;
  }

  public boolean isEditable() {
    return true;
  }

  protected String name, value;

  protected boolean deleted;

  static public class FeatureEntryComparator implements Comparator {

    public FeatureEntryComparator(int col) {
      this.col = col;
    }

    public int compare(Object o1, Object o2) {
      if (o1 instanceof TagEntry && o2 instanceof TagEntry) {
	TagEntry e1 = (TagEntry) o1;
	TagEntry e2 = (TagEntry) o2;
	Object v1 = e1.getColumnValue(col);
	Object v2 = e2.getColumnValue(col);
	if (v1 != null && v2 != null) {
	  switch (col) {
	  case NAME_COLUMN:
	  case VALUE_COLUMN:
	    return (v1.toString()).compareTo(v2.toString());
	  default:
	    return ((String) v1).compareTo((String) v2);
	  }
	}
      }
      return 0;
    }

    protected int col;
  }

}
